package handle

import (
	"fmt"
	"server/game/model"
	"server/share/config"

	"github.com/hwcer/cosgo/random"
	"github.com/hwcer/cosgo/registry"
	"github.com/hwcer/updater/dataset"
	"github.com/hwcer/yyds/context"
	"github.com/hwcer/yyds/errors"
	"github.com/hwcer/yyds/players/player"
)

func init() {
	Register(&Shop{})
}

type Shop struct {
}

func (this *Shop) Caller(node *registry.Node, handle *context.Context) interface{} {
	f := node.Method().(func(*Shop, *context.Context) interface{})
	return f(this, handle)
}

// Getter 获取所有商店(可刷新,限购)信息
// 仅仅获取数据库信息，并不会强制刷新，使用Shop/goods 获取特定商店信息并刷新商品
// 如果结果中没有对应商店信息，说明还没初始化
// 建议使用goods获取并检查更新商店信息
func (this *Shop) Getter(c *context.Context) interface{} {
	rows := map[string]any{}
	coll := c.Player.Collection(config.ITypeShop)
	coll.Range(func(id string, doc *dataset.Document) bool {
		rows[id] = doc.Any()
		return true
	})

	return rows
}

// Refresh 手动刷新刷新货架
//
// id int32 商店ID
func (this *Shop) Refresh(c *context.Context) interface{} {
	id := c.GetInt32("id")
	if id == 0 {
		return c.Error("id empty")
	}
	cfg := config.Data.Shop[id]
	if cfg == nil {
		return c.Error("shop id not exist")
	}

	if cfg.RefreshMod == config.Data.ShopRefreshMod.None {
		return false
	}

	var canRefresh bool
	for _, v := range cfg.RefreshSub {
		if v.Id > 0 && v.Num > 0 {
			canRefresh = true
			c.Player.Sub(v.Id, v.Num)
		}
	}
	if !canRefresh {
		return c.Error("refresh sub items empty")
	}
	return this.mayRefresh(c.Player, cfg.RefreshMod, id, nil)
}

// Goods 商店信息 如果玩家盯着商店面板,倒计时结束时,使用此接口更新货物信息
//
// id int32 商店ID
func (this *Shop) Goods(c *context.Context) interface{} {
	id := c.GetInt32("id")
	if id == 0 {
		return errors.ErrArgEmpty
	}
	shopConfig := config.Data.Shop[id]
	if shopConfig == nil {
		return errors.ErrConfigEmpty
	}
	if shopConfig.RefreshMod == config.Data.ShopRefreshMod.None {
		return false
	}
	var shopData *model.Shop
	shopHandle := c.Player.Collection(config.ITypeShop)
	if i := shopHandle.Get(id); i == nil {
		return this.mayRefresh(c.Player, shopConfig.RefreshMod, id, nil)
	} else {
		shopData = i.(*model.Shop)
	}
	now := c.Unix()
	switch shopConfig.RefreshMod {
	case config.Data.ShopRefreshMod.Common:
		if shopData.Expire <= now {
			return this.mayRefresh(c.Player, shopConfig.RefreshMod, id, nil)
		}
	case config.Data.ShopRefreshMod.Super:
		return this.mayRefresh(c.Player, shopConfig.RefreshMod, id, shopData.Shelves)
	}
	return true
}

// refresh 模式3 逐条检查
func (this *Shop) mayRefresh(p *player.Player, mod int32, iid int32, data map[int32]model.ShopShelf) any {
	ids := config.GetShopRefreshShelf(iid)
	if len(ids) == 0 {
		return errors.ErrArgEmpty
	}
	now := p.Unix()
	shelves := map[int32]model.ShopShelf{}
	var changed bool
	for _, k := range ids {
		if v, ok := data[k]; ok && v.Expire > now {
			shelves[k] = v
			continue
		}
		if v, err := this.refreshGoods(p, k); err != nil {
			return err
		} else if v != nil {
			changed = true
			shelves[k] = *v
		}
	}

	if changed {
		up := dataset.Update{}
		up["update"] = p.Unix()
		up["shelves"] = shelves
		if mod == config.Data.ShopRefreshMod.Common {
			shopConfig := config.Data.Shop[iid]
			if expire, err := p.Times.ExpireWithArray(shopConfig.RefreshRule...); err != nil {
				return err
			} else {
				up["expire"] = expire
			}
		}
		coll := p.Collection(config.ITypeShop)
		coll.Set(iid, up)
	}
	return nil
}

// needRefresh 是否需要刷新
func (this *Shop) needRefresh(stock int32, goods []int32) bool {
	if len(goods) <= 1 && stock == 0 {
		return false
	}
	return true
}
func (this *Shop) refreshGoods(p *player.Player, id int32) (r *model.ShopShelf, err error) {
	shelf := config.Data.ShopShelf[id]
	if !this.needRefresh(shelf.Stock, shelf.Goods) {
		return nil, nil
	}

	rnd := random.Random{}
	for _, k := range shelf.Goods {
		c := config.Data.ShopGoods[k]
		if c != nil && c.GetVal() > 0 {
			rnd.Add(k, c.Val)
		}
	}
	v := rnd.Roll()
	if v < 0 {
		return nil, errors.Errorf(0, "商店格子随机组错误:%d", id)
	}
	r = &model.ShopShelf{Key: v}

	var rule []int64
	if ssr := config.Data.ShopShelfRefresh[id]; ssr != nil {
		rule = ssr.RefreshRule
	}
	if len(rule) >= 2 && rule[0] > 0 && rule[1] > 0 {
		if r.Expire, err = p.Times.ExpireWithArray(rule...); err != nil {
			return
		}
	}
	return
}

// Purchase 快速购买
//
//		id int 商品ID，ShopPurchase.id
//	 num int 购买次数
func (this *Shop) Purchase(c *context.Context) interface{} {
	id := c.GetInt32("id")
	num := c.GetInt32("num")
	if num <= 0 {
		return errors.ErrArgEmpty
	}
	shopPurchase := config.Data.ShopPurchase[id]
	if shopPurchase == nil {
		return errors.ErrConfigEmpty
	}
	ttl, err := c.Player.Times.ExpireWithArray(shopPurchase.RefreshRule...)
	if err != nil {
		return nil
	}

	iid := config.Data.ShopIdConst.Purchase
	handle := c.Player.Collection(config.ITypeShop)
	handle.Select(iid)
	if err = c.Player.Data(); err != nil {
		return err
	}
	var data *model.Shop
	if i := handle.Get(iid); i != nil {
		data = i.(*model.Shop)
	} else {
		data = &model.Shop{}
	}

	v := data.Shelves[id]
	now := c.Unix()
	if ttl > 0 && v.Expire <= now {
		v.Expire = ttl
		v.Value = 0
		v.Key = id
	}
	if shopPurchase.Limit > 0 {
		if s := shopPurchase.Limit - v.Value; s <= 0 {
			return c.Error("Out of stock")
		} else if num > s {
			num = s
		}
	}
	for i := v.Value + 1; i <= num; i++ {
		shopPurchasePrice := config.GetShopPurchasePrice(id, i)
		if shopPurchasePrice == nil {
			return c.Errorf(0, "shopPurchasePrice num not exist:%d", i)
		}
		c.Player.Sub(shopPurchase.Sub, shopPurchasePrice.Num)
	}
	c.Player.Add(id, shopPurchase.Num*num)
	v.Value += num
	k := fmt.Sprintf("shelves.%d", id)
	update := dataset.Update{}
	update[k] = v
	handle.Set(iid, update)
	return true
}

// Submit 购买入口
//
// id   int32 货架(格子)ID
//
// num 	int32 购买次数
func (this *Shop) Submit(c *context.Context) interface{} {
	id := c.GetInt32("id")
	shelfConfig := config.Data.ShopShelf[id]
	if shelfConfig == nil {
		return c.Error("shelf id not exist")
	}
	num := c.GetInt32("num")
	if num <= 0 {
		return c.Error("num empty")
	}
	shopConfig := config.Data.Shop[shelfConfig.ShopId]
	c.Player.Emit(config.Data.Events.ShopBuy, num)
	if shopConfig.RefreshMod == config.Data.ShopRefreshMod.None {
		return this.basic(c.Player, id, num)
	} else {
		return this.senior(c.Player, id, num)
	}
}

// basic 普通购买
func (this *Shop) goods(p *player.Player, data *model.Shop, shelfId int32, keys []int32, num int32, up dataset.Update) any {
	//折扣信息
	ds := this.discount(p, shelfId)
	dv := data.GetDiscount(shelfId)
	dk := fmt.Sprintf("discount.%d", shelfId)
	var discount, donate int32
	if ds > 0 {
		dv.MayRefresh(ds)
		c := config.Data.ShopShelfDiscount[ds]
		if c.Value == 0 || dv.Value < c.Value {
			discount, donate = c.Discount, c.Donate
		}
		dv.Value++
		up[dk] = dv

	} else if dv.Key != ds {
		dv.MayRefresh(ds)
		up[dk] = dv
	}

	for _, k := range keys {
		if shopGoods := config.Data.ShopGoods[k]; shopGoods != nil {
			p.SubItems(shopGoods.Sub, num*(100-discount), 100)
			p.AddItems(shopGoods.Item, num*(100+donate), 100)
			p.Verify.Auto(shopGoods)
		}
	}
	return nil
}

// discount
func (this *Shop) discount(p *player.Player, id int32) int32 {
	dis := config.GetShopShelfDiscount(id)
	if len(dis) == 0 {
		return 0
	}
	for _, k := range dis {
		c := config.Data.ShopShelfDiscount[k]
		if c == nil {
			continue
		}
		if _, err := p.Times.Verify(c.Times); err == nil {
			return k
		}
	}
	return 0
}

// basic 普通购买  带库存的非刷新格子(终身限购)
func (this *Shop) basic(p *player.Player, id int32, num int32) any {
	shelf := config.Data.ShopShelf[id]
	if shelf == nil {
		return errors.Error("shelf id not exist")
	}

	iid := shelf.ShopId
	handle := p.Collection(config.ITypeShop)

	handle.Select(iid)
	if err := p.Data(); err != nil {
		return err
	}
	var data *model.Shop
	if i := handle.Get(iid); i != nil {
		data = i.(*model.Shop)
	} else {
		data = &model.Shop{}
	}
	update := dataset.Update{}
	defer func() {
		if len(update) > 0 {
			update["update"] = p.Unix()
			handle.Set(iid, update)
		}
	}()
	if !this.needRefresh(shelf.Stock, shelf.Goods) {
		return this.goods(p, data, id, shelf.Goods, num, update)
	}

	v := data.Shelves[id]
	if stock := shelf.Stock - v.Value; stock <= 0 {
		return errors.Errorf(0, "not enough stock")
	} else if num > stock {
		num = stock
	}

	v.Value += num
	k := fmt.Sprintf("shelves.%d", id)
	update[k] = v
	update["sales"] = data.Sales + 1

	return this.goods(p, data, id, shelf.Goods, num, update)
}

// senior 黑市购买
func (this *Shop) senior(p *player.Player, id int32, num int32) any {
	shelf := config.Data.ShopShelf[id]
	if shelf == nil {
		return errors.Error("shelf id not exist")
	}
	iid := shelf.ShopId
	coll := p.Collection(config.ITypeShop)
	coll.Select(iid)
	if err := p.Data(); err != nil {
		return err
	}

	var data *model.Shop
	if i := coll.Get(iid); i == nil {
		return errors.Errorf(0, "商店未初始化")
	} else {
		data = i.(*model.Shop)
	}
	update := dataset.Update{}
	defer func() {
		if len(update) > 0 {
			update["update"] = p.Unix()
			coll.Set(iid, update)
		}
	}()
	if !this.needRefresh(shelf.Stock, shelf.Goods) {
		return this.goods(p, data, id, shelf.Goods, num, update)
	}

	now := p.Unix()
	if data.Expire > 0 && data.Expire < now {
		return errors.Errorf(0, "商店已过期,请刷新商店")
	}
	v, ok := data.Shelves[id]
	//配置修改导致未随机入库
	if !ok {
		if i, err := this.refreshGoods(p, id); err != nil {
			return err
		} else if i != nil {
			v = *i
		} else {
			return errors.Errorf(0, "不可能的未知错误")
		}
	}
	if v.Expire > 0 && v.Expire < now {
		return errors.Errorf(0, "商品已过期,请刷新商店")
	}

	if shelf.Stock > 0 {
		if stock := shelf.Stock - v.Value; stock <= 0 {
			return errors.Errorf(0, "not enough stock")
		} else if num > stock {
			num = stock
		}
	}

	shopGoods := config.Data.ShopGoods[v.Key]
	if shopGoods == nil {
		return errors.Errorf(0, "shop goods not exist,ShelfId:%v,GoodsId%v", id, v.Key)
	}

	v.Value += num
	k := fmt.Sprintf("shelves.%d", id)
	update[k] = v
	update["sales"] = data.Sales + 1

	return this.goods(p, data, id, []int32{v.Key}, num, update)
}
